﻿// MNN_PFLD.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "UltraFace.hpp"
#include <opencv2/opencv.hpp>
#include <string.h>
#include "net.h"
#include <thread>

#include<windows.h>
#include <mmsystem.h>
#include<dsound.h>
#pragma comment(lib, "WINMM.LIB")

using namespace std;

#define KUANG_W 100 //最小人脸框-宽
#define KUANG_H 100 //最小人脸框-高
#define MOUTH_KUANG_W_H 1.0 //嘴巴张合大小比（0.4为闭嘴 0.8~1.2为打哈欠张嘴度）

extern auto play_music = chrono::steady_clock::now();
extern int play_flag = false;
//线程要做的事情就写在这个线程函数中
void GetSumT()
{
	unsigned seed;
	seed = time(0);
	srand(seed);
	int number = rand() % 6 + 1;
	cout << "播放音频" <<number<< endl;
	if (number>3) {
		PlaySound(TEXT("./music/putonghua.wav"), NULL, SND_FILENAME | SND_ASYNC);
	}
	else if (number<3) {
		PlaySound(TEXT("./music/yueyu.wav"), NULL, SND_FILENAME | SND_ASYNC);
	}
}
void GetSumT_2()
{
	cout << "播放音乐" << endl;
	PlaySound(TEXT("./music/shaonian.wav"), NULL, SND_FILENAME | SND_ASYNC);
}

//计算欧式距离
float twoPointDistance(float x1, float y1, float x2, float y2)
{
	return  pow(pow(x1 - x2, 2) + pow(y1 - y2, 2), 0.5);
}

//人脸98点标记
static int landmark_detector(cv::Mat& bgr, float* landmarks, int img_size = 112)
{
	ncnn::Net pfld;
	pfld.load_param("./model/pfld-sim.param");
	pfld.load_model("./model/pfld-sim.bin");
	ncnn::Mat out;
	/*char  input_blob_name[] = "input";
	char  output_blob_name[] = "output";*/

	char  input_blob_name[] = "input_1";
	char  output_blob_name[] = "415";

	//    pfld.opt.use_vulkan_compute = true;
	int N = 1;

	ncnn::Mat in = ncnn::Mat::from_pixels_resize(bgr.data, ncnn::Mat::PIXEL_BGR, bgr.cols, bgr.rows, img_size, img_size);
	const float norm_vals[3] = { 1 / 255.f, 1 / 255.f, 1 / 255.f };
	in.substract_mean_normalize(0, norm_vals);
	for (int i = 0; i < N; i++) {
		ncnn::Extractor ex = pfld.create_extractor();
		ex.input(input_blob_name, in);
		ex.extract(output_blob_name, out);
	}
	for (int j = 0; j < out.w; j++)
	{
		landmarks[j] = out[j];
	}
	return 0;
}

int demo_face(cv::Mat& image) {

	string mnn_path = "D:/C++/MNN_PFLD/MNN_PFLD/models/onnx";
	UltraFace ultraface(mnn_path, 320, 240, 4, 0.65); // config model input
	auto start = chrono::steady_clock::now();
	vector<FaceInfo> face_info;
	ultraface.detect(image, face_info);
	vector<cv::Point> mouth_array;
	int h, w;
	//定义嘴部位置
	vector<cv::Point> *p = &mouth_array;

	for (auto face : face_info) 
	{
		int x = face.x1;
		int y = face.y1;
		w = face.x2 - face.x1;
		h = face.y2 - face.y1;
		if (w > KUANG_W && h > KUANG_H) 
		{
		cv::Point pt1(face.x1, face.y1);
		cv::Point pt2(face.x2, face.y2);
		cv::rectangle(image, pt1, pt2, cv::Scalar(0, 255, 0), 2);
		cv::Mat faces = image(cv::Rect(x, y, w, h));
		cv::resize(faces, faces, cv::Size(112, 112));
		//cv::putText(image, to_string(i), cv::Point(landmarks[i * 2] * w + x, landmarks[i * 2 + 1] * h + y-13), cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(0, 0, 255), 1);
			float landmarks[212];
			landmark_detector(faces, landmarks, 112);
			int j = 0;
			for (int i = 0; i < 106; i++) 
			{
				if (i < 98) {
					cv::circle(image, cv::Point(landmarks[i * 2] * w + x, landmarks[i * 2 + 1] * h + y),
						2, cv::Scalar(0, 0, 255), -1);
					if (78 <= i && i <= 80) 
					{
						mouth_array.push_back(cv::Point(landmarks[i * 2] * w + x, landmarks[i * 2 + 1] * h + y));
					}
					else if (85 <= i && i<= 95) 
					{
						mouth_array.push_back(cv::Point(landmarks[i * 2] * w + x, landmarks[i * 2 + 1] * h + y));
					}
				}
			}
		}
	}
	int j = 0;
	float mouth_height = 0.0;
	float mouth_weight = 0.0;
	for (vector<cv::Point>::iterator it = mouth_array.begin(); it != mouth_array.end(); it++,j++) ///第二种调用方法  
	{
		if (j==0)
		{
			mouth_height += twoPointDistance((*it).x, (*it).y, (*(it+4)).x, (*(it+ 4)).y);
		}
		if (j==1)
		{
			mouth_height += twoPointDistance((*it).x, (*it).y, (*(it +3)).x, (*(it +3)).y);
		}
		if (j == 2)
		{
			mouth_height += twoPointDistance((*it).x, (*it).y, (*(it +1)).x, (*(it+1)).y);
		}
		if (j == 6)
		{
			mouth_weight += twoPointDistance((*it).x, (*it).y, (*(it+4)).x, (*(it +4)).y);

		}
		//cout << (*it).x << " "<< (*it).y<<endl;
	}
	float mouth_w_h = mouth_height / (2.0*mouth_weight);
	cout << "height: " << mouth_height << "weight: " << mouth_weight << endl;
	cout << "h: " << h << "w: " << w << endl;

	auto play_music_2 = chrono::steady_clock::now();
	chrono::duration<double> elapsed_1 = play_music_2 - play_music;
	float play_time = elapsed_1.count() * 1000;
	cout << "play time: " << play_time << "ms" << endl;
	//防溢出，刷新时间
	if (play_time > 10000) {
		play_music = chrono::steady_clock::now();
		play_flag = false;
	}
	cout << "aaa : " << mouth_weight / w << endl;
	if (mouth_w_h > MOUTH_KUANG_W_H) {
		cv::putText(image, "Sleep!", cv::Point(20,100), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 2);
		if (play_time > 6000 or play_flag==false) {
			play_flag = true;
			play_music = chrono::steady_clock::now();
			thread first(GetSumT); //子线程播放提示
			first.join(); //主线程要等待子线程执行完毕
		}
		
	}
	else if (mouth_weight/w > 0.39 && mouth_weight / w < 0.45) {
		cv::putText(image, "Smile!", cv::Point(20,100), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 2);
	}
	//else if (mouth_weight / w > 0.44) {
	//	thread first(GetSumT_2); //子线程播放提示
	//	first.join(); //主线程要等待子线程执行完毕
	//}
	cout << endl;
	auto end = chrono::steady_clock::now();
	chrono::duration<double> elapsed = end - start;
	cout << "all time: " << elapsed.count()*1000 << "ms" << endl;
}
int only_face(cv::Mat& image) {

	string mnn_path = "D:/C++/MNN_PFLD/MNN_PFLD/models/onnx";
	UltraFace ultraface(mnn_path, 320, 240, 4, 0.65); // config model input
	auto start = chrono::steady_clock::now();
	vector<FaceInfo> face_info;
	ultraface.detect(image, face_info);
	vector<cv::Point> mouth_array;
	int h, w;
	//定义嘴部位置
	vector<cv::Point> *p = &mouth_array;

	for (auto face : face_info)
	{
		int x = face.x1;
		int y = face.y1;
		w = face.x2 - face.x1;
		h = face.y2 - face.y1;
		if (w > KUANG_W && h > KUANG_H)
		{
			cv::Point pt1(face.x1, face.y1);
			cv::Point pt2(face.x2, face.y2);
			cv::rectangle(image, pt1, pt2, cv::Scalar(0, 255, 0), 2);
		}
	}
	
	cout << endl;
	auto end = chrono::steady_clock::now();
	chrono::duration<double> elapsed = end - start;
	cout << "all time: " << elapsed.count() * 1000 << "ms" << endl;
}
void show_result(int type, cv::String filePath) {

	float scaleW = 1.5; // 定义新图像的大小，宽度缩小到50%
	float scaleH = 1.5;  //定义新图像的大小，高度缩小到50%
	if (type == 1) {
		cv::VideoCapture capture(0);
		while (true) {
			cv::TickMeter timer;
			timer.start();
			cv::Mat frame;
			capture >> frame;
			if (frame.empty())
				break;
			cv::Mat img = frame;
			demo_face(img);
			cv::Mat dst;
			int width = int(img.cols * scaleW);
			//定义想要扩大或者缩小后的宽度，src.cols为原图像的宽度，乘以80%则得到想要的大小，并强制转换成int型
			int height = int(img.rows * scaleH);
			//定义想要扩大或者缩小后的高度，src.cols为原图像的高度，乘以80%则得到想要的大小，并强制转换成int型
			resize(img, dst, cv::Size(width, height));//缩放图像
			// 显示检测结果
			timer.stop();
			string fps = "FPS: " + to_string(1000 / timer.getTimeMilli());
			cv::putText(dst, fps, cv::Point(20, 25), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
			cv::imshow("test", dst);
			int key;
			key=cv::waitKey(1);
			if (key == 27) {
				break;
				
			}
		}
		capture.release();
	}
	else {
		cv::String imagepath = filePath;
		cv::Mat img = cv::imread(imagepath, 1);
		demo_face(img);
		cv::Mat dst;
		int width = int(img.cols * scaleW);
		//定义想要扩大或者缩小后的宽度，src.cols为原图像的宽度，乘以80%则得到想要的大小，并强制转换成int型
		int height = int(img.rows * scaleH);
		//定义想要扩大或者缩小后的高度，src.cols为原图像的高度，乘以80%则得到想要的大小，并强制转换成int型
		resize(img, dst, cv::Size(width, height));//缩放图像
		// 显示检测结果
		cv::imshow("test", dst);
		cv::waitKey(0);
	}
}

int main()
{
	show_result(1,"m");
	return 0;
}
